package procsim;

public class MDemultiplexer implements Element{
    private MSignal inSig, cSigM;
    private Signal cSig[];
    private Signal enable = new Signal(1);
    private MSignalArray result;
    protected int outNum;
    private int cNum, numOfBits, cP=0;
    protected boolean enableNotSet = true;
    protected String name = "DP";
    public MDemultiplexer(int nob, int num){
        outNum=Util.roundToNextMultiple(num); // zaokruzivanje na sledeci stepen dvojke
        cNum=(int)Math.getExponent(outNum); // broj kontrolnih signala je ld(inNum)
        inSig=new MSignal(1, 0);
        cSig=new Signal[cNum];
        numOfBits=nob;
        MSignal[] tmp = new MSignal[outNum];
        for(int i=0; i<num; i++)
            tmp[i]=new MSignal(numOfBits, 0);
        result=new MSignalArray(tmp);
    }
    public MDemultiplexer(int nob, int number, MSignal in, Signal control[]){
        this(nob, number);
        if(in!=null) in.addElement(this);
        inSig=in;
        for(int i=0; i<cNum; i++, cP++){
            if(control[i]!=null) control[i].addElement(this);
            cSig[i]=control[i];
        }
    }
    public MDemultiplexer(int nob, int number, MSignal in, MSignal control){
        this(nob, number);
        if(in!=null) in.addElement(this);
        if(control!=null) control.addElement(this);
        inSig=in;
        cSigM=control;
    }
    public MDemultiplexer setIn(MSignal sig){
        if(sig!=null) sig.addElement(this);
        inSig=sig;
        return this;
    }
    public MDemultiplexer addControl(Signal sig){
        if(cSigM!=null) // Ne mesamo babe i zabe
            System.err.println("Ne mogu se dodati novi signali");
        else if(cP<cNum){
            if(sig!=null) sig.addElement(this);
            cSig[cP++]=sig;
        }
        else
            System.err.println("Nema vise mesta za nove signale");
        return this;
    }
    public MDemultiplexer setResult(MSignalArray sig){
        result=sig;
        return this;
    }
    public MDemultiplexer setEnableBit(Signal sig){
        if(enable!=null) enable.addElement(this);
        enable = sig;
        enableNotSet = false;
        return this;
    }
    public void setName(String name){
        this.name = name;
    }
    @Override
    public MDemultiplexer tick(){
        if(enable!=null && enable.isNull()){
            MSignal[] res=new MSignal[outNum];
            for(int i=0; i<outNum; i++)
                res[i]=new MSignal(numOfBits, 0);
            result.set(new MSignalArray(res));
            return this;
        }
        Signal[] sigarray;
        if(cSigM==null)
            sigarray=cSig;
        else
            sigarray=cSigM.getBits();
        int index=Util.binaryArray2Int(Util.signalArray2IntArray(sigarray));
        MSignal[] res=new MSignal[outNum];
        for(int i=0; i<outNum; i++){
            if(i==index) res[i]=inSig;
            else res[i]=new MSignal(numOfBits, 0);
        }
        if(result!=null) result.set(new MSignalArray(res));
        return this;
    }
    @Override
    public MSignalArray result() {
        return result;
    }
    @Override
    public String toString(){
        return ""+result;
    }
    @Override
    public void updateSignal(Sig sig) { // proveriti i testirati!
        boolean changed = false;
        if(inSig!=null && inSig==sig){
            inSig.set(sig.get(), false);
            changed = true;
        }
        if(cSigM!=null && cSigM==sig){
            cSigM.set(sig.get(), false);
            changed = true;
        }
        if(enable!=null && enable==sig){
            enable.set(sig.get(), false);
            changed = true;
        }
        for(int i=0; i<cSig.length; i++){
            if(cSig[i]!=null && cSig[i]==sig){
                cSig[i].set(sig.get(), false);
                changed = true;
            }
        }
        if(changed) tick();
    }
}
